#ifndef SERVER_TRANSMIT_TRANSMIT_SERVER_H
#define SERVER_TRANSMIT_TRANSMIT_SERVER_H

#include <brpc/server.h>
#include <butil/logging.h>

#include <memory>

#include "channel.h"
#include "etcd.h"
#include "mysql_session.h"
#include "rabbitmq.h"
#include "transmite.pb.h"

namespace chat {
class MsgTransmitServiceImpl : public MsgTransmitService {
   public:
    MsgTransmitServiceImpl(const ServiceManagerPtr service_manager,
                           const std::string& user_service_name,
                           const MQClientPtr& mq_client,
                           const std::string& exchange_name,
                           const std::string& routing_key,
                           const std::shared_ptr<odb::mysql::database>& db)
        : user_service_name_(user_service_name),
          service_manager_(service_manager),
          mq_client_(mq_client),
          exchange_name_(exchange_name),
          routing_key_(routing_key),
          session_member_table_(std::make_shared<ChatSessionMemberTable>(db)) {}

    void GetTransmitTarget(::google::protobuf::RpcController* controller,
                           const ::chat::NewMessageReq* request,
                           ::chat::GetTransmitTargetRsp* response,
                           ::google::protobuf::Closure* done);

   private:
    std::string user_service_name_;                // 用户管理方法
    ServiceManagerPtr service_manager_ = nullptr;  // 用于获取用户管理的rpc调用

    // 用于实现消息的持久化
    MQClientPtr mq_client_ = nullptr;
    std::string exchange_name_;
    std::string routing_key_;

    ChatSessionMemberTablePtr session_member_table_ = nullptr;
};

class MsgTransmitServer {
   public:
    MsgTransmitServer(const RegistryPtr& register_client,
                      const DiscoveryPtr& discovery_client,
                      const std::shared_ptr<brpc::Server> brpc_server,
                      const std::shared_ptr<odb::mysql::database> odb_client)
        : register_client_(register_client),
          discovery_client_(discovery_client),
          brpc_server_(brpc_server),
          odb_client_(odb_client) {}

    /**
     * @brief 启动rpc服务
     */
    void start() { brpc_server_->RunUntilAskedToQuit(); }

   private:
    RegistryPtr register_client_ = nullptr;
    DiscoveryPtr discovery_client_ = nullptr;

    std::shared_ptr<brpc::Server> brpc_server_ = nullptr;

    std::shared_ptr<odb::mysql::database> odb_client_ = nullptr;
};

using MsgTransmitServerPtr = std::shared_ptr<MsgTransmitServer>;

class MsgTransmitServerBuilder {
   public:
    /**
     * @brief 创建服务注册客户端
     * @param register_name[in]: 服务名称
     * @param etcd_host[in]: etcd服务器 ip:port
     * @param access_host[in]: 外部访问 ip:port
     */
    void makeRegisterClient(const std::string& register_name,
                            const std::string& etcd_host,
                            const std::string& access_host);

    /**
     * @brief 创建rpc服务管理对象
     *
     * @param file_service_name[in]: 要关心的服务名称
     */
    void makeServiceManager(const std::string& file_service_name);

    /**
     * @brief 创建服务发现客户端
     * @param etcd_host[in]: etcd服务器 ip:port
     * @param base_service[in]: 服务发现时的根目录
     */
    void makeDiscoveryClient(const std::string& etcd_host,
                             const std::string& base_service);

    /**
     * @brief 创建 brpc 服务
     * @param port[in]: brpc 服务器端口
     * @param idle_timeout_sec[in]: 连接空闲超时时间，超时后连接关闭
     * @param num_threads[in]: 线程数量
     */
    void makeBrpcServer(const uint16_t port, const int idle_timeout_sec,
                        const int num_threads);

    /**
     * @brief 创建 ODB 客户端
     *
     * @param max_pool[in]: 最大连接池数量
     * @param user[in]: mysql用户名
     * @param password[in]: 对应用户名密码
     * @param db[in]: 要链接到的数据库名称
     * @param ip[in]: mysql服务器ip
     * @param port[in]: mysql服务器端口
     * @param charset[in]: 所采用的字符集
     */
    void makeOdbClient(const int max_pool, const std::string& user,
                       const std::string& password, const std::string& db,
                       const std::string& ip, const uint16_t port,
                       const std::string& charset);

    /**
     * @param user[in]: 客户端用户
     * @param password[in]: 用户密码
     * @param host[in]: rabbitmq服务主机地址，形如: 127.0.0.1:5672
     * @param exchange_name[in]: 交换机名字
     * @param queue_name[in]: 队列名字
     * @param routing_key[in]: 路由键
     */
    void makeMQClient(const std::string& user, const std::string& password,
                      const std::string& host, const std::string& exchange_name,
                      const std::string& queue_name,
                      const std::string& routing_key);

    /**
     * @brief 构造一个 UserServer对象 并返回
     */
    MsgTransmitServerPtr build();

   private:
    RegistryPtr register_client_ = nullptr;

    ServiceManagerPtr service_manager_ = nullptr;
    DiscoveryPtr discovery_client_ = nullptr;
    std::string user_service_name_;

    std::shared_ptr<brpc::Server> brpc_server_ = nullptr;

    std::shared_ptr<odb::mysql::database> odb_client_ = nullptr;

    MQClientPtr mq_client_ = nullptr;
    std::string exchange_name_;
    std::string routing_key_;
};
}  // namespace chat

#endif  // SERVER_TRANSMIT_TRANSMIT_SERVER_H